<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html><head><title>Programming in Lua : 13.1</title>
<link rel="stylesheet" type="text/css" href="pil.css">
</head>
<body>
<p class="warning">
<A HREF="contents.html"><IMG TITLE="Programming in Lua (first edition)" SRC="capa.jpg" ALT="" ALIGN="left"></A>This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.<BR>The third edition targets Lua 5.2 and is available at <A HREF="http://www.amazon.com/exec/obidos/ASIN/859037985X/theprogrammil3-20">Amazon</A> and other bookstores.<BR>By buying the book, you also help to <A HREF="../donations.html">support the Lua project</A>.
</p>
<table width="100%" class="nav">
<tr>
<td width="10%" align="left"><a href="13.html"><img border="0" src="left.png" alt="Previous"></a></td>
<td width="80%" align="center"><a href="contents.html"><font face="Helvetica,Arial,sanserif">
<font color="gray">Programming in </font><font color="blue"> Lua</font>
</font></a></td>
<td width="10%" align="right"><a href="13.2.html"><img border="0" src="right.png" alt="Next"></a></td>
</tr>
<tr>
<td width="10%" align="left"></td>
<td width="80%" align="center"><a href="contents.html#P2">Part II. Tables and Objects</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="contents.html#13">Chapter 13. Metatables and Metamethods</a></td>
<td width="10%" align="right"></td></tr>
</table>
<hr/>
<p><h2>13.1 &ndash; Arithmetic Metamethods</h2>

<p>In this section, we will introduce a simple example
to explain how to use metatables.
Suppose we are using tables to represent sets,
with functions to compute the union of two sets,
intersection, and the like.
As we did with lists,
we store these functions inside a table
and we define a constructor to create new sets:
<pre>
    Set = {}
    
    function Set.new (t)
      local set = {}
      for _, l in ipairs(t) do set[l] = true end
      return set
    end
    
    function Set.union (a,b)
      local res = Set.new{}
      for k in pairs(a) do res[k] = true end
      for k in pairs(b) do res[k] = true end
      return res
    end
    
    function Set.intersection (a,b)
      local res = Set.new{}
      for k in pairs(a) do
        res[k] = b[k]
      end
      return res
    end
</pre>
To help checking our examples,
we also define a function to print sets:
<pre>
    function Set.tostring (set)
      local s = "{"
      local sep = ""
      for e in pairs(set) do
        s = s .. sep .. e
        sep = ", "
      end
      return s .. "}"
    end
    
    function Set.print (s)
      print(Set.tostring(s))
    end
</pre>

<p>Now, we want to make the addition operator (`<code>+</code>&acute;)
compute the union of two sets.
For that, we will arrange that all tables
representing sets share a metatable
and this metatable will define how they react to the addition operator.
Our first step is to create a regular
table that we will use as the metatable for sets.
To avoid polluting our namespace,
we will store it in the <code>Set</code> table:
<pre>
    Set.mt = {}    -- metatable for sets
</pre>
The next step is to modify the <code>Set.new</code> function,
which creates sets.
The new version has only one extra line,
which sets <code>mt</code> as the metatable for the
tables that it creates:
<pre>
    function Set.new (t)   -- 2nd version
      local set = {}
      setmetatable(set, Set.mt)
      for _, l in ipairs(t) do set[l] = true end
      return set
    end
</pre>
After that, every set we create with <code>Set.new</code> will have that
same table as its metatable:
<pre>
    s1 = Set.new{10, 20, 30, 50}
    s2 = Set.new{30, 1}
    print(getmetatable(s1))          --> table: 00672B60
    print(getmetatable(s2))          --> table: 00672B60
</pre>

<p>Finally, we add to the metatable the so-called metamethod,
a field <code>__add</code> that describes how to perform the union:
<pre>
    Set.mt.__add = Set.union
</pre>
Whenever Lua tries to add two sets,
it will call this function,
with the two operands as arguments.

<p>With the metamethod in place,
we can use the addition operator to do set unions:
<pre>
    s3 = s1 + s2
    Set.print(s3)  --> {1, 10, 20, 30, 50}
</pre>
Similarly, we may use the multiplication
operator to perform set intersection:
<pre>
    Set.mt.__mul = Set.intersection
    
    Set.print((s1 + s2)*s1)     --> {10, 20, 30, 50}
</pre>

<p>For each arithmetic operator there is a
corresponding field name in a metatable.
Besides <code>__add</code> and <code>__mul</code>,
there are <code>__sub</code> (for subtraction),
<code>__div</code> (for division),
<code>__unm</code> (for negation),
and <code>__pow</code> (for exponentiation).
We may define also the field <code>__concat</code>,
to define a behavior for the concatenation operator.

<p>When we add two sets,
there is no question about what metatable to use.
However, we may write an expression that mixes two values
with different metatables, for instance like this:
<pre>
    s = Set.new{1,2,3}
    s = s + 8
</pre>
To choose a metamethod, Lua does the following:
(1) If the first value has a metatable with an <code>__add</code> field,
Lua uses this value as the metamethod,
independently of the second value;
(2) otherwise, if the second value has a metatable with an <code>__add</code> field,
Lua uses this value as the metamethod;
(3) otherwise, Lua raises an error.
Therefore, the last example will call <code>Set.union</code>,
as will the expressions <code>10 + s</code> and <code>"hy" + s</code>.

<p>Lua does not care about those mixed types,
but our implementation does.
If we run the <code>s = s + 8</code> example,
the error we get will be inside <code>Set.union</code>:
<pre>
    bad argument #1 to `pairs' (table expected, got number)
</pre>
If we want more lucid error messages,
we must check the type of the operands explicitly
before attempting to perform the operation:
<pre>
    function Set.union (a,b)
      if getmetatable(a) ~= Set.mt or
         getmetatable(b) ~= Set.mt then
        error("attempt to `add' a set with a non-set value", 2)
      end
      ...  -- same as before
</pre>

<hr/>
<table width="100%" class="nav">
<tr valign="top">
<td width="90%" align="left">
<small>
  Copyright &copy; 2003&ndash;2004 Roberto Ierusalimschy.  All rights reserved.
</small>
</td>
<td width="10%" align="right"><a href="13.2.html"><img border="0" src="right.png" alt="Next"></a></td>
</tr>
</table>


</body></html>

